package example.jnidexload;

import android.app.ActivityManager;
import android.content.Context;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

/**
 * Created by xuxingcan on 16-11-20.
 */
public class XposedEntry implements IXposedHookLoadPackage {
    public static String pkgName = "wechat.simpleforwarder";
    private static final String soName = "libJpush.so";
    private static final String enDexName = "appcompat_v4.dex";
    private static final String gsonDexName = "gson.dex";

    @Override
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (!loadPackageParam.packageName.contains("tencent.mm")) {
            return;
        }
        try {
            findAndHookMethod("android.app.Application", loadPackageParam.classLoader, "onCreate", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Context mContext = (Context) param.thisObject;
                    String processName = getCurProcessName(mContext);
                    XposedBridge.log("processName = " + processName);
                    if (!mContext.getPackageName().equalsIgnoreCase(processName)) {
                        return;
                    }
                    File soDir = mContext.getDir(pkgName.replace(".", "_") + "_so", Context.MODE_PRIVATE);
                    File dexDir = mContext.getDir(pkgName.replace(".", "_") + "_dex", Context.MODE_PRIVATE);
                    Context pkgContext = mContext.createPackageContext(XposedEntry.pkgName, Context.CONTEXT_IGNORE_SECURITY);
                    File soFile = new File(soDir, soName);
                    copyFileFromAssets(pkgContext.getAssets().open(soName), soFile);
                    copyFileFromAssets(pkgContext.getAssets().open(enDexName), new File(dexDir, enDexName));
                    copyFileFromAssets(pkgContext.getAssets().open(gsonDexName), new File(dexDir, gsonDexName));
                    System.load(soFile.getAbsolutePath());
                    Class xposedClazz = (Class) JniUtil.getXClass(
                            mContext,
                            soDir.getAbsolutePath(),
                            dexDir.getAbsolutePath()
                    );
//                    XposedBridge.log("getSignatureHashCode = " + JniUtil.getSignatureHashCode(mContext));
                    Method init = xposedClazz.getMethod(JniUtil.getXMethodName(), XC_LoadPackage.LoadPackageParam.class, Context.class);
                    init.invoke(xposedClazz.newInstance(), loadPackageParam, mContext);
//                    try {
//                        Context mContext = (Context) param.thisObject;
//                        File opt = mContext.getDir("dex", Context.MODE_PRIVATE);
//                        XposedBridge.log("opt = " + opt.getAbsolutePath());
//                        DexClassLoader parent = new DexClassLoader(new File(Environment.getExternalStorageDirectory(), "dex/gson.dex").getAbsolutePath(), opt.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
//                        DexClassLoader cl = new DexClassLoader(new File(Environment.getExternalStorageDirectory(), "dex/classes.dex").getAbsolutePath(), opt.getAbsolutePath(), null, parent);
//                        Class libProviderClazz = cl.loadClass("fu.ck.hooklibrary.XposedInit");
//                        Method init = libProviderClazz.getMethod("init", XC_LoadPackage.LoadPackageParam.class);
//                        init.invoke(libProviderClazz.newInstance(), loadPackageParam);
//                        for (File file : opt.listFiles()) {
//                            file.delete();
//                        }
//                    } catch (Exception e) {
//                        XposedBridge.log(e);
//                    }
                }
            });
        } catch (Exception exception) {
            XposedBridge.log(exception);
        }
    }

    private String getCurProcessName(Context context) {
        int pid = android.os.Process.myPid();
        ActivityManager mActivityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) {
            if (appProcess.pid == pid) {
                return appProcess.processName;
            }
        }
        return null;
    }

    private void copyFileFromAssets(InputStream inStream, File file) throws Exception {
        if (file.exists()) {
            file.delete();
        }
        FileOutputStream fs = new FileOutputStream(file);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inStream.read(buffer)) != -1) {
            fs.write(buffer, 0, length);
        }
        fs.close();
        inStream.close();
    }
}
